﻿using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
using Newtonsoft.Json;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.ServiceComponent.DAC.Service;
using System.Reflection;
using T.FAS.Runtime.Base.Entity;
using System.Data;
using T.FAS.Runtime.Base.Dao;

namespace T.FAS.Runtime.DataModel.Dao
{
    public class DataQueryELBDao : DaoService<DataQuery>, IDataQueryDao
    {
        public const string MetaDataID = DataModelConst.DQMetaType;
        public const string MetaDataName = "数据查询";
        public override string TableName => "FAS_DataQuery";
        public override string IDColumnName => "ID";
        public override List<string> ExceptColumnName { get; } = 
            DaoUtil.GetExceptionColumn<DataQuery>(
            new List<string>
            {
                EntityTools.ProjectBranchID,
                nameof(DataQuery.RelatedMetaDataID),
            });

        private const string _enumQueryType = "QueryType";
        private const string _enumTreeListType = "TreeListType";
        private readonly DataQuerySourceELBDao _dataQuerySourceELBDao = new DataQuerySourceELBDao();
        private readonly DataQueryJoinELBDao _dataQueryJoinELBDao = new DataQueryJoinELBDao();
        private readonly DataQueryColumnELBDao _dataQueryColumnELBDao = new DataQueryColumnELBDao();
        private readonly DataQueryFilterELBDao _dataQueryFilterELBDao = new DataQueryFilterELBDao();
        private readonly DataQuerySortELBDao _dataQuerySortELBDao = new DataQuerySortELBDao();
        private readonly DataQueryParamELBDao _dataQueryParamELBDao = new DataQueryParamELBDao();
        private readonly DataQuerySubQueryELBDao _dataQuerySubQueryELBDao = new DataQuerySubQueryELBDao();

        public DataQueryELBDao() : base()
        {
            DBName = "TFAS";
        }

        #region Override
        public override DataQuery ConvertToObject(Dictionary<string, PropertyInfo> columns, DataRow row)
        {
            columns.Remove("IsDistinct");
            columns.Remove(_enumQueryType);
            columns.Remove(_enumTreeListType);

            DataQuery data = base.ConvertToObject(columns, row);

            if (row[_enumQueryType] != null)
            {
                var str = Convert.ToString(row[_enumQueryType]);
                if (!string.IsNullOrEmpty(str))
                    data.QueryType = (QueryType)Enum.Parse(typeof(QueryType), str);
            }

            if (row[_enumTreeListType] != null)
            {
                var str = Convert.ToString(row[_enumTreeListType]);
                if (!string.IsNullOrEmpty(str))
                    data.TreeListType = (TreeListType)Enum.Parse(typeof(TreeListType), str);
            }

            string isDistinctVal = row["IsDistinct"]?.ToString();
            if (!string.IsNullOrEmpty(isDistinctVal))
            {
                if (int.TryParse(isDistinctVal, out int isDistinctInt))
                {
                    data.IsDistinct = isDistinctInt == 0 ? false : true;
                }
                else
                    data.IsDistinct = false;
            }
            else
                data.IsDistinct = false;
            return data;
        }

        public override Dictionary<string, object> GetDataMapping(DataQuery data)
        {

            var mapping = base.GetDataMapping(data);
            mapping.Remove(_enumQueryType);
            mapping.Add(_enumQueryType, (int)data.QueryType);

            mapping.Remove(_enumTreeListType);
            mapping.Add(_enumTreeListType, (int)data.TreeListType);

            return mapping;
        }

        public override Dictionary<string, PropertyInfo> GetColumns()
        {
            return DaoServiceExtension.GetAllColumns<DataQuery>(base.GetColumns());
        }

        #endregion

        /// <summary>
        /// 删除DQ
        /// </summary>
        /// <param name="dqId"></param>
        public void DeleteDataQuery(string dqId)
        {
            try
            {
                _dataQuerySourceELBDao.DeleteDataQuerySource(dqId);
                _dataQueryJoinELBDao.DeleteDataQueryJoin(dqId);
                _dataQueryColumnELBDao.DeleteDataQueryColumn(dqId);
                _dataQueryFilterELBDao.DeleteDataQueryFilter(dqId);
                _dataQuerySortELBDao.DeleteDataQuerySort(dqId);
                _dataQueryParamELBDao.DeleteDataQueryParam(dqId);
                _dataQuerySubQueryELBDao.DeleteDataQuerySubQuery(dqId);

                this.Delete(new List<string> { dqId });
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.DeleteError, e.Message, e);
            }
        }

        /// <summary>
        /// 删除DataQuery
        /// </summary>
        /// <param name="dqIds"></param>
        public void BatchDeleteDataQueryByIds(List<string> dqIds)
        {
            try
            {
                List<string> sqls = new List<string>();
                foreach (string dqId in dqIds)
                {
                    sqls.Add(string.Format(DaoUtil.DeleteSQLWithNoParam, this.TableName, this.IDColumnName, dqId));
                }
                base.DB.ExecSqlStatement(sqls.ToArray());
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.DeleteError, e.Message, e);
            }
        }

        /// <summary>
        /// 删除DQ
        /// </summary>
        /// <param name="dqIds"></param>
        public void BatchDeleteDataQuery(List<string> dqIds)
        {
            try
            {
                _dataQuerySourceELBDao.BatchDeleteDataQuerySource(dqIds);
                _dataQueryJoinELBDao.BatchDeleteDataQueryJoin(dqIds);
                _dataQueryColumnELBDao.BatchDeleteDataQueryColumn(dqIds);
                _dataQueryFilterELBDao.BatchDeleteDataQueryFilter(dqIds);
                _dataQuerySortELBDao.BatchDeleteDataQuerySort(dqIds);
                _dataQueryParamELBDao.BatchDeleteDataQueryParam(dqIds);
                _dataQuerySubQueryELBDao.BatchDeleteDataQuerySubQuery(dqIds);

                BatchDeleteDataQueryByIds(dqIds);
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.DeleteError, e.Message, e);
            }
        }

        /// <summary>
        /// 获取DQ
        /// </summary>
        /// <param name="dqId"></param>
        /// <returns></returns>
        public DataQuery GetDataQueryByID(string dqId)
        {
            try
            {
                var dq = this.GetObject(dqId);
                InitializeDQ(dq);
                return dq;
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.RetrieveError, e.Message, e);
            }
        }

        /// <summary>
        /// 获取DQ集合
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public List<DataQuery> GetDataQuerys(Dictionary<string, string> filter)
        {
            var result = new List<DataQuery>();
            List<object> objects = base.GetObjectsByFilter($"1=1'");
            if (objects != null)
            {
                objects.ForEach(obj =>
                {
                    var dq = obj as DataQuery;
                    InitializeDQ(dq);
                    result.Add(dq);
                });
            }
            return result;
        }

        /// <summary>
        /// 保存DQ
        /// </summary>
        /// <param name="dataQuery"></param>
        public void SaveDataQuery(DataQuery dataQuery)
        {
            this.Add(new List<object> { dataQuery });
            if (dataQuery.DataQuerySources != null && dataQuery.DataQuerySources.Count > 0)
                _dataQuerySourceELBDao.CreateDataQuerySource(dataQuery.DataQuerySources);

            if (dataQuery.DataQueryJoins != null && dataQuery.DataQueryJoins.Count > 0)
                _dataQueryJoinELBDao.CreateDataQueryJoin(dataQuery.DataQueryJoins);

            if (dataQuery.DataQueryColumns != null && dataQuery.DataQueryColumns.Count > 0)
                _dataQueryColumnELBDao.CreateDataQueryColumn(dataQuery.DataQueryColumns);

            if (dataQuery.DataQueryFilters != null && dataQuery.DataQueryFilters.Count > 0)
                _dataQueryFilterELBDao.CreateDataQueryFilter(dataQuery.DataQueryFilters);

            if (dataQuery.DataQuerySorts != null && dataQuery.DataQuerySorts.Count > 0)
                _dataQuerySortELBDao.CreateDataQuerySort(dataQuery.DataQuerySorts);

            if (dataQuery.DataQueryParams != null && dataQuery.DataQueryParams.Count > 0)
                _dataQueryParamELBDao.CreateDataQueryParam(dataQuery.DataQueryParams);

            if (dataQuery.SubQuerys != null && dataQuery.SubQuerys.Count > 0)
                _dataQuerySubQueryELBDao.CreateDataQuerySubQuery(dataQuery.SubQuerys);
        }

        /// <summary>
        /// 保存DQ
        /// </summary>
        /// <param name="dataQueries"></param>
        public void BatchSaveDataQuery(List<DataQuery> dataQueries)
        {
            List<DataQuerySource> sources = new List<DataQuerySource>();
            List<DataQueryJoin> joins = new List<DataQueryJoin>();
            List<DataQueryColumn> columns = new List<DataQueryColumn>();
            List<DataQueryFilter> filters = new List<DataQueryFilter>();
            List<DataQuerySort> sorts = new List<DataQuerySort>();
            List<DataQueryParam> paramS = new List<DataQueryParam>();
            List<DataQuerySubQuery> subQueries = new List<DataQuerySubQuery>();

            foreach (DataQuery dataQuery in dataQueries)
            {
                if (dataQuery.DataQuerySources != null && dataQuery.DataQuerySources.Count > 0)
                    sources.AddRange(dataQuery.DataQuerySources);

                if (dataQuery.DataQueryJoins != null && dataQuery.DataQueryJoins.Count > 0)
                    joins.AddRange(dataQuery.DataQueryJoins);

                if (dataQuery.DataQueryColumns != null && dataQuery.DataQueryColumns.Count > 0)
                    columns.AddRange(dataQuery.DataQueryColumns);

                if (dataQuery.DataQueryFilters != null && dataQuery.DataQueryFilters.Count > 0)
                    filters.AddRange(dataQuery.DataQueryFilters);

                if (dataQuery.DataQuerySorts != null && dataQuery.DataQuerySorts.Count > 0)
                    sorts.AddRange(dataQuery.DataQuerySorts);

                if (dataQuery.DataQueryParams != null && dataQuery.DataQueryParams.Count > 0)
                    paramS.AddRange(dataQuery.DataQueryParams);

                if (dataQuery.SubQuerys != null && dataQuery.SubQuerys.Count > 0)
                    subQueries.AddRange(dataQuery.SubQuerys);
            }
            _dataQuerySourceELBDao.CreateDataQuerySource(sources);
            _dataQueryJoinELBDao.CreateDataQueryJoin(joins);
            _dataQueryColumnELBDao.CreateDataQueryColumn(columns);
            _dataQueryFilterELBDao.CreateDataQueryFilter(filters);
            _dataQuerySortELBDao.CreateDataQuerySort(sorts);
            _dataQueryParamELBDao.CreateDataQueryParam(paramS);
            _dataQuerySubQueryELBDao.CreateDataQuerySubQuery(subQueries);
            this.Add(dataQueries);
        }

        #region Private Funcs
        private DataQuery InitializeDQ(DataQuery dataQuery)
        {
            try
            {
                if (dataQuery == null) return null;
                dataQuery.DataQuerySources = _dataQuerySourceELBDao.GetDataQuerySources(dataQuery.ID).OrderBy(o => o.Sort).ToList();
                dataQuery.DataQueryJoins = _dataQueryJoinELBDao.GetDataQueryJoins(dataQuery.ID).OrderBy(o => o.Sort).ToList();
                dataQuery.DataQueryColumns = _dataQueryColumnELBDao.GetDataQueryColumns(dataQuery.ID).OrderBy(o => o.Sort).ToList();
                dataQuery.DataQueryFilters = _dataQueryFilterELBDao.GetDataQueryFilters(dataQuery.ID).OrderBy(o => o.Sort).ToList();
                dataQuery.DataQuerySorts = _dataQuerySortELBDao.GetDataQuerySorts(dataQuery.ID).OrderBy(o => o.Sort).ToList();
                dataQuery.DataQueryParams = _dataQueryParamELBDao.GetDataQueryParams(dataQuery.ID).OrderBy(o => o.Sort).ToList();
                dataQuery.SubQuerys = _dataQuerySubQueryELBDao.GetDataQuerySubQuerys(dataQuery.ID).OrderBy(o => o.Sort).ToList();
                return dataQuery;
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.InitError, e.Message, e);
            }
        }
        #endregion
    }
}